Lab 06 - Robot Operating System 2 - interactions through publishing

Robot Operating System 2 - interactions through publishing

IRiM and Fossbot4AI logos

1. Activity Identity

Activity title Introduction to Robotics
Topic Robotics / ROS 2 / Simulation and Hardware
Authors Institute of Robotics and Machine Intelligence
Dominik Belter, Jakub Chudzinski, Marcin Czajka, Kamil Młodzikowski
Target learners Bachelor (Computer Science / IT, Robotics)
Estimated duration 1.5 hours
Difficulty level Beginner
FOSSBot environment Hybrid (Simulator and physical FOSSBot)
Licence CC BY 4.0

2. Learning Objectives and Competences

ID Learning outcome Related competences Assessment evidence
LO1 Students will be able to publish messages to a topic from the command line with ros2 topic pub, controlling the robot’s motion by setting the fields of a geometry_msgs/msg/Twist message. Robotics middleware knowledge; sensor and actuator interfacing. Screenshot of a ros2 topic pub command next to the robot moving / /odom updating (Submission item 1).
LO2 Students will be able to distinguish single (--once) from continuous (--rate) publishing, stop a robot safely with a zero-velocity command, and explain what happens when two publishers share one topic. Computational thinking; reasoning about concurrency in a distributed system. Screenshot of rqt_graph with two publishers on /cmd_vel (Submission item 2).
LO3 Students will be able to apply the identical publishing workflow to a physical FOSSBot over a shared network and explain how its behaviour differs from the simulator. Tool selection for working with a robot; operating real hardware safely over a network. Photo or short video of the real robot moving, with the published command visible (Submission item 3).

3. Prerequisites

4. Required Material and Setup

Category Item Version / Quantity Notes
Hardware Workstation 1 per student The same Docker-capable Linux PC used in Lab 05. See Step 1.
Software FOSSBotEduSim simulator latest from main branch Already cloned and built into the ros2_fossbot_edu Docker image during Lab 05. If you no longer have the image, rebuild it as described in Lab 05.
Hardware Physical FOSSBot 1 per group (final step only) Instructor-provided and powered on. It exposes the same ROS 2 topics as the simulator (/cmd_vel, /odom, /scan).
Hardware Lab Wi-Fi router / AP 1 per room (final step only) Instructor-provided. The robot and your workstation join the same network so they can discover each other.

Tip: Every simulation step (1 to 5) works without the physical robot. If hardware is not available, complete those steps and read through Step 6 so you know how the real-robot workflow differs.

5. Safety, Ethics and Accessibility Notes

The simulation steps carry over the operational notes from Lab 05:

Step 6 is the first time in this course that you command real hardware, so it adds physical safety:

6. Scenario and Problem Statement

In Lab 05 you watched the robot from the outside: you listed topics and printed their messages with ros2 topic echo. That is the subscriber half of the picture.

A robot is only useful when you can command it. Publishing is how every controller, from a joystick to a navigation planner, ultimately talks to a robot: it writes messages onto a topic that the robot’s drivers subscribe to. In this lab you will take the publisher role yourself. You will hand-craft velocity commands for the simulated FOSSBot, then send the very same commands to a real FOSSBot across the network.

7. Lab Workflow

Phase Student action Expected output Time
1. Prepare Start the container and launch the simulator Gazebo + RViz2 running, /cmd_vel visible 10 min
2. Inspect the channel Look at /cmd_vel and the Twist message type Understanding of which fields move the robot 10 min
3. Publish once Send one Twist with ros2 topic pub --once The robot keeps moving until a zero Twist stops it 15 min
4. Publish continuously Drive with ros2 topic pub --rate, then stop with a zero Twist The robot drives a path and halts reliably 20 min
5. Two publishers Run teleop and a pub on /cmd_vel at once, inspect rqt_graph An understanding of what happens when publishers compete 15 min
6. Real robot Repeat the workflow on a physical FOSSBot over Wi-Fi The real robot moves in response to your published command 15 min
7. Reflect Answer the analysis questions Short written analysis 5 min

8. Step-by-Step Instructions

Before you start. Capture evidence as you go. The full list of artifacts you will hand in is in Section 10. Relevant tasks below are marked with a Capture for submission note.

Step 1 - Environment preparation

You will reuse the ros2_fossbot_edu Docker image that was built in Lab 05; here you only start it. If you no longer have that image, rebuild it from the FOSSBotEduSim repository on your workstation before continuing:

git clone https://github.com/LRMPUT/FOSSBotEduSim.git
cd FOSSBotEduSim
bash build_image.sh
  1. Start the container from the FOSSBotEduSim directory on your workstation:
bash start_container.sh

Warning: If your workstation has no NVIDIA GPU, use bash start_container_no_gpus.sh instead, exactly as in Lab 05.

  1. Launch the simulator from inside the container:
ros2 launch fossbot_educational_description single.launch.py world:=simple_shapes.sdf

Two windows open: a Gazebo window with the FOSSBot in a world full of boxes, and an RViz2 window. Leave both running.

  1. Open a second terminal attached to the same container (run this on the host):
docker exec -it ros2_fossbot_edu bash

This second shell already has ROS 2 and the FOSSBot workspace sourced from ~/.bashrc. You will use it to inspect topics while the simulator runs in the first terminal.

Expected result: Gazebo and RViz2 are running, and ros2 topic list in the second terminal shows /cmd_vel, /odom and /scan among the topics.

Step 2 - Inspect the command channel

Before publishing, look at the topic you are about to write to and the message it carries. In the second terminal:

ros2 topic info /cmd_vel
ros2 interface show geometry_msgs/msg/Twist

ros2 topic info tells you the message type of /cmd_vel is geometry_msgs/msg/Twist, and how many publishers and subscribers it currently has. The Twist message looks like this:

Vector3  linear
        float64 x
        float64 y
        float64 z
Vector3  angular
        float64 x
        float64 y
        float64 z

The FOSSBot is a differential-drive robot: two driven wheels and a non-holonomic constraint, which is the same kind of motion model as the turtlesim turtle. It can only drive along its own forward axis and rotate about the vertical axis. Of the six numbers in a Twist, only two have any effect:

The other four fields stay at 0.0.

Terminal output of ros2 topic info /cmd_vel and ros2 interface show geometry_msgs/msg/Twist

ros2 topic info /cmd_vel reports the message type and that one subscriber (the bridge) is listening, while ros2 interface show geometry_msgs/msg/Twist reveals the two Vector3 fields.

Tip: You do not need to memorise message type names. Type ros2 interface show geometry_msgs/msg/Tw and press Tab, and the terminal completes it for you. The same trick works for topic and package names.

Task 2.1

Looking at the Twist structure above, state which two fields move this particular robot and why the other four are ignored. You will use this answer in Step 3.

Expected result: You can point to linear.x and angular.z and explain that a differential-drive robot has only those two degrees of freedom.

Step 3 - Publish a single command

Now you take the publisher role. In the second terminal, send a single Twist that asks the robot to move forward slowly:

ros2 topic pub --once /cmd_vel geometry_msgs/msg/Twist "{linear: {x: 0.2}, angular: {z: 0.0}}"

The --once flag publishes the message exactly one time and then exits. Watch the Gazebo window: the robot starts driving forward and keeps going, even though ros2 topic pub has already finished.

The simulator’s velocity controller remembers the last command it received and keeps applying it until a new one arrives. One message is enough to set the robot moving, and nothing stops it except another message. Stop it now by publishing a zero-velocity command:

ros2 topic pub --once /cmd_vel geometry_msgs/msg/Twist "{linear: {x: 0.0}, angular: {z: 0.0}}"

Warning: Keep this zero Twist command at hand for the whole lab. It is the one command that reliably stops the robot, in simulation and on real hardware.

The physical FOSSBot you will use in Step 6 behaves the same way: its bridge keeps resending your last command to the robot. Many other robots, however, treat a command as valid only for a short time and stop the wheels when no new one arrives. This safety feature is called a watchdog.

To watch the effect numerically, open a third terminal (docker exec -it ros2_fossbot_edu bash on the host) and echo the odometry:

ros2 topic echo /odom --once

Run it before publishing the forward command, again a few seconds after, and once more after the zero command. Compare the position values: x grows while the robot drives and stays put once you have stopped it.

Terminal showing odom position before publishing, the ros2 topic pub command, and odom position after, with x increased

Before publishing, the robot is at the origin (x near 0). Shortly after a single ros2 topic pub --once forward command, /odom reports x of about 0.19, and the value keeps growing until a zero Twist is published.

Task 3.1

Send a command that makes the robot rotate in place, without moving forward:

ros2 topic pub --once /cmd_vel geometry_msgs/msg/Twist "{linear: {x: 0.0}, angular: {z: 0.5}}"

Confirm in Gazebo that the robot turns on the spot rather than driving forward, then stop it with the zero Twist.

Expected result: A single forward command sets the robot driving until you publish the zero Twist; a single rotation command spins it in place until you stop it the same way.

Capture for submission: screenshot the ros2 topic pub command together with the robot displaced in Gazebo (or the changed /odom numbers).

Step 4 - Publish continuously and stop safely

On the FOSSBot, simulated or real, a single command is enough to keep the robot moving, but you cannot rely on that in general: on a robot with a watchdog the wheels stop a fraction of a second after the last command. Real controllers, from a joystick to a navigation planner, therefore publish repeatedly. The --rate flag does this for you: it republishes the same message at a fixed frequency until you stop it.

  1. In the second terminal, start a continuous forward command at 10 Hz:
ros2 topic pub --rate 10 /cmd_vel geometry_msgs/msg/Twist "{linear: {x: 0.2}}"

The robot now drives forward with a fresh command arriving every 0.1 s. On a robot with a watchdog, this steady stream is what keeps it moving.

  1. In the third terminal, watch the position climb:
ros2 topic echo /odom
  1. Stop the robot. First press Ctrl+C in the second terminal to end the continuous publish. The robot does not stop, in simulation or on the real FOSSBot: it keeps applying the last command it received. Publish one explicit zero-velocity command:
ros2 topic pub --once /cmd_vel geometry_msgs/msg/Twist "{linear: {x: 0.0}, angular: {z: 0.0}}"

Warning: Get into the habit of sending this zero Twist after every Ctrl+C. On the real robot in Step 6 it is what reliably halts the hardware, and an explicit zero command stops any robot, whatever its driver does.

Task 4.1

Drive the robot in a rough square. Alternate between a few seconds of forward motion and a short rotation, using --rate publishes and Ctrl+C between them. Remember that the robot keeps executing the last command after Ctrl+C, so start the next leg promptly:

# forward leg
ros2 topic pub --rate 10 /cmd_vel geometry_msgs/msg/Twist "{linear: {x: 0.2}}"
# Ctrl+C, then turn roughly 90 degrees
ros2 topic pub --rate 10 /cmd_vel geometry_msgs/msg/Twist "{angular: {z: 0.5}}"
# Ctrl+C, repeat

Watch the position and orientation fields of /odom change as you go.

Expected result: The robot follows your commands while you publish, and a single zero Twist reliably brings it to a stop.

Capture for submission: screenshot the --rate command beside the moving robot and the updating /odom terminal.

Step 5 - Two publishers on one topic

A topic does not belong to a single publisher. Any number of publishers can write to /cmd_vel, and ROS 2 does not decide which one “wins”; it simply delivers every message to the subscribers in the order they arrive. You can see this directly.

  1. In the second terminal, start the keyboard teleoperator from Lab 05:
ros2 run teleop_twist_keyboard teleop_twist_keyboard
  1. In the third terminal, start a competing continuous command:
ros2 topic pub --rate 10 /cmd_vel geometry_msgs/msg/Twist "{angular: {z: 0.5}}"

Now drive with the teleop keys in the second terminal. The robot twitches and fights itself: each subscriber message is whichever command arrived most recently, so the motion alternates between your keypresses and the steady rotation.

  1. Open a fourth terminal and start the graph visualiser:
rqt_graph

Find the /cmd_vel topic and notice that two arrows now point into it: the teleop_twist_keyboard node and the ros2 topic pub process are both publishers on the same topic.

rqt_graph showing two publisher nodes both connected to the /cmd_vel topic feeding ros_gz_bridge

Two publishers (here two ros2 topic pub commands, shown as the /_ros2cli_... nodes on the left) both feed the single /cmd_vel topic, which the /ros_gz_bridge node subscribes to. ROS 2 delivers every message from both; it does not pick a winner.

This is why production robots place a multiplexer between many command sources and the wheels. The twist_mux package (already installed in the container) listens to several command topics, applies a priority order, and forwards only the winner to /cmd_vel, so a high-priority source such as an emergency stop always overrides a joystick or a planner.

When you are done, stop both publishers (Ctrl+C in each terminal) and send the zero Twist from Step 4.

Task 5.1

With both publishers running, take a screenshot of rqt_graph showing two arrows feeding into /cmd_vel.

Tip: If the graph looks empty or shows only one publisher, change the top-left dropdown to Nodes/Topics (all) and click the refresh icon.

Expected result: The robot responds erratically while two publishers compete, and rqt_graph shows both of them connected to /cmd_vel.

Capture for submission: the rqt_graph screenshot with two publishers on /cmd_vel.

Step 6 - Do the same on a real FOSSBot

A real FOSSBot runs its own ROS 2 nodes and exposes the same topics as the simulator. Instead of launching a simulator, you join the robot’s network and let ROS 2 discover it.

Connect to the robot by following Connecting to real robot, then come back here. Do not launch the simulator. When ros2 topic list shows the robot’s /cmd_vel, /odom and /scan, you are ready for the tasks below, which use the same commands you ran in simulation.

Task 6.1

Clear the space around the robot and have the stop command ready. Publish the same single forward command you used in Step 3, keeping the speed small, then stop it with the zero Twist from Step 4:

ros2 topic pub --once /cmd_vel geometry_msgs/msg/Twist "{linear: {x: 0.1}, angular: {z: 0.0}}"
# then, to be sure it is stopped:
ros2 topic pub --once /cmd_vel geometry_msgs/msg/Twist "{linear: {x: 0.0}, angular: {z: 0.0}}"

The real robot behaves exactly like the simulated one: it keeps driving until the zero Twist arrives, because the bridge keeps resending your last command. Its watchdog only cuts the motors if the bridge stops or the Wi-Fi link is lost for more than 0.5 s; it is a last-resort safety net, not a way to stop the robot.

Task 6.2

In another terminal of your lab container, prepared as described in Connecting to real robot, echo the robot’s sensors and compare them with what you saw in simulation:

ros2 topic echo /odom --once
ros2 topic echo /scan --once

Warning: Clear space around the robot before every publish, and keep one hand near the keyboard to send the zero Twist. A real robot does not stop when you stop typing or press Ctrl+C. The bridge keeps sending your last command until you publish a zero Twist.

Expected result: The real FOSSBot moves in response to your published Twist, and its /odom and /scan messages have the same structure as the simulator’s.

Capture for submission: a photo or short video of the real robot moving, with the published command visible on screen.

9. Analysis Questions

  1. In Step 3 a single --once Twist set the robot moving, and it kept moving after ros2 topic pub had exited, both in simulation and on the real FOSSBot in Step 6. Why? Many robots instead stop automatically when commands stop arriving (a watchdog). What are the advantages and risks of each approach?

  2. In Step 5 two publishers wrote to /cmd_vel at the same time. What did the robot actually do, and why does ROS 2 allow a second publisher rather than rejecting it? Give one situation where having several publishers on one command topic is genuinely useful.

  3. In Step 4 you published a zero Twist after pressing Ctrl+C. Why does stopping the publisher not stop the robot, and why is an explicit zero Twist the reliable way to halt it, even on a robot that has a watchdog?

  4. In Step 6 you sent the real robot the same commands as the simulator. Did it move the same way for the same Twist? Give two reasons why a real robot’s motion can differ from the simulated one.

10. Submission Requirements

11. References and Open Licence

The Creative Commons Attribution 4.0 International (CC BY 4.0) license allows users to share, copy, distribute, and adapt the work, even for commercial purposes, as long as proper credit is given to the original creator.

EU funding disclaimer

Funded by the European Union. Views and opinions expressed are however those of the author(s) only and do not necessarily reflect those of the European Union or the European Education and Culture Executive Agency (EACEA). Neither the European Union nor EACEA can be held responsible for them.